package com.itms.tool.utils;

import java.lang.ref.WeakReference;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.os.AsyncTask;
import android.support.v4.app.FragmentManager;
import android.widget.ImageView;

public class ImageFetcher {

	private static final String TAG = "image_cache";
	private static final int FADE_IN_TIME = 200;
	private static final Executor DUAL_EXECUTOR = Executors.newFixedThreadPool(2);
	private Bitmap mLoadingBitmap;
	private Context mContext;
	private ImageCache mCache;
	private int mWidth;
	private int mHeight;
	
	public ImageFetcher(Context ctx, FragmentManager fm) {
		mContext = ctx;
		RetainFragment rf = (RetainFragment) fm.findFragmentByTag(TAG);
		if (rf == null) {
			rf = new RetainFragment();
			fm.beginTransaction().add(rf, TAG).commit();
		}
		mCache = (ImageCache) rf.getObject();
		if (mCache == null) {
			mCache = new ImageCache();
			rf.setObject(mCache);
		}
	}
	
	public void setLoadingBitmap(Bitmap loading) {
		mLoadingBitmap = loading;
	}
	
	public void setImage(String mPath, ImageView iv, Bitmap bmp) {
		TransitionDrawable td = new TransitionDrawable(new Drawable[] {
				new ColorDrawable(android.R.color.transparent),
				new BitmapDrawable(mContext.getResources(), bmp) });
		iv.setImageDrawable(td);
		td.startTransition(FADE_IN_TIME);
	}
	
	public void setSize(int width, int height) {
		mWidth = width;
		mHeight = height;
	}

	public void setSize(int size) {
		setSize(size, size);
	}
	
	/** loads image from specified path into the imageView
	 * @return true if image is in cache, false otherwise **/
	public boolean loadImage(String path, ImageView iv) {
		Bitmap bmp = mCache.get(path);
		if (bmp != null) {
			iv.setImageBitmap(bmp);
			return true;
		} else {
			iv.setImageBitmap(mLoadingBitmap);
			ImageWorker imgFetcher = (ImageWorker) iv.getTag();
			if (imgFetcher != null && imgFetcher.mPath.equals(path)) {
				// work is already in progress 
				return false;
			}
			if (imgFetcher == null) {
				imgFetcher = new ImageWorker(path, iv);
			} else { // imgFetcher.mImgInfo != ii
				imgFetcher.cancel(true);
				imgFetcher = new ImageWorker(path, iv);
			}
			synchronized (iv) {
				iv.setTag(imgFetcher);
			}
			imgFetcher.executeOnExecutor(DUAL_EXECUTOR);
			return false;
		}
	}

	public class ImageWorker extends AsyncTask<Void, Void, Bitmap> {

		private String mPath;
		private WeakReference<ImageView> mImageViewReference;
		private BitmapLoader mBmpLoader = new BitmapLoader();

		public ImageWorker(String path, ImageView iv) {
			mPath = path;
			mImageViewReference = new WeakReference<ImageView>(iv);
		}

		@Override
		protected Bitmap doInBackground(Void... params) {
			Bitmap bmp = mBmpLoader.getScaledBitmap(mPath, mWidth, mHeight);
			if (bmp != null) {
				mCache.put(mPath, bmp);
			}
			return bmp;
		}

		@Override
		protected void onPostExecute(Bitmap bmp) {
			ImageView attachedView = getAttachedView();
			if (attachedView != null && bmp != null) {
				setImage(mPath, attachedView, bmp);
				detach();
			}
		}

		@Override
		protected void onCancelled() {
			super.onCancelled();
			detach();
		}

		private ImageView getAttachedView() {
			ImageView iv = mImageViewReference.get();
			if (iv != null && iv.getTag() == this) {
				return iv;
			}
			return null;
		}

		private void detach() {
			ImageView attachedView = mImageViewReference.get();
			if (attachedView != null) {
				synchronized (attachedView) {
					if (attachedView.getTag() == this) {
						attachedView.setTag(null);
						mImageViewReference.clear();
					}
				}
			}
		}
	}

}
